﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using Robocode;
using Robocode.Control;
using Robocode.Control.Events;

namespace GPforRobocode
{
    static class RobotTool
    {
        static RobocodeEngine _engine;
        static string _sampleCode;

        static public double ERC
        {
            get;
            set;
        }

        static public BattleResults FirstTank
        {
            get;
            private set;
        }

       static public BattleResults SecondTank
        {
            get;
            private set;
        }

       static public bool Visible
       {
           get { return _engine.Visible; }
           set { _engine.Visible = value; }
       }

        #region Robocode主程式相關
        
        static RobotTool() 
        {
            // Create the RobocodeEngine
           _engine = new RobocodeEngine(@"..\"); 

            StreamReader sr = new StreamReader(@"..\robots\GpRobot\samplecode.txt");
            _sampleCode = sr.ReadToEnd();
            sr.Close();
        }

        static public void InitRobocode() 
        {
            // Add battle event handlers
            _engine.BattleCompleted += new BattleCompletedEventHandler(BattleCompleted);
            //_engine.BattleMessage += new BattleMessageEventHandler(BattleMessage);
            _engine.BattleError += new BattleErrorEventHandler(BattleError);

            // Show the Robocode battle view
            _engine.Visible = false;

            // Disable log messages from Robocode
            RobocodeEngine.LogMessagesEnabled = false;
        }

        /// <summary>
        /// 程式結束前須呼叫
        /// </summary>
        static public void CloseRobocode() 
        {
            // Cleanup our RobocodeEngine
            _engine.Close();
        }

        /// <summary>
        /// Robocode主程式進行一場坦克戰鬥
        /// </summary>
        /// <param name="botParam">傳入要加入戰鬥的坦克名字</param>

        public static void RunBattle(params string[] botParam) 
        {
            // Setup the battle specification
            int numberOfRounds = 10;
            BattlefieldSpecification battlefield = new BattlefieldSpecification(800, 600); // 800x600
            string playerList = null;
            for (int i = 0; i < botParam.Length; i++)
            {
                if (i > 2) break;
                playerList += ',' + botParam[i];
            }
            //string playerList = botParam.Aggregate((workingSentence, next) => workingSentence + ',' + next);
            RobotSpecification[] selectedRobots = _engine.GetLocalRepository(playerList);
            BattleSpecification battleSpec = new BattleSpecification(numberOfRounds, battlefield, selectedRobots);

            // Run our specified battle and let it run till it is over
            _engine.RunBattle(battleSpec, true);
        }

        // Called when the battle is completed successfully with battle results
        static void BattleCompleted(BattleCompletedEvent e)
        {
            Console.WriteLine("-- Battle has completed --");

            // Print out the sorted results with the robot names

            int i = 0;
            Console.WriteLine("Battle results:");
            foreach (BattleResults result in e.IndexedResults)
            {
                Console.WriteLine(i++ + "  " + result.TeamLeaderName + ": " + result.Score);
            }

            if (e.IndexedResults.Length > 0) FirstTank = e.IndexedResults[0];
            if(e.IndexedResults.Length > 1) SecondTank = e.IndexedResults[1];
        }

        // Called when the game sends out an information message during the battle
        static void BattleMessage(BattleMessageEvent e)
        {
            Console.WriteLine("Msg> " + e.Message);
        }

        // Called when the game sends out an error message during the battle
        static void BattleError(BattleErrorEvent e)
        {
            Console.WriteLine("Err> " + e.Error);
        }

        #endregion

        #region Robot AI 相關

        public static void GenerateCsCode(string csName, string logic1, string logic2, string logic3, string logic4, string logic5, string logic6) 
        {
            List<string> temp = new List<string>();
            temp.Add(logic1);
            temp.Add(logic2);
            temp.Add(logic3);
            temp.Add(logic4);
            temp.Add(logic5);
            temp.Add(logic6);
            GenerateCsCode(csName, temp);

        }
        public static void GenerateCsCode(string csName, List<string> logic)
        {
            string code = _sampleCode.Replace("#{ROBOTNAME}", csName);
            code = code.Replace("#{GPLOGICMove}", logic[0]);
            code = code.Replace("#{GPLOGICTurnTank}", logic[1]);
            code = code.Replace("#{GPLOGICTurnGun}", logic[2]);
            code = code.Replace("#{MAINmove}", logic[3]);
            code = code.Replace("#{MAINTurnTank}", logic[4]);
            code = code.Replace("#{MAINTurnGun}", logic[5]);            		
            code = code.Replace("Enemy", "e.");
            code = code.Replace("#{ERC}", ERC.ToString());

            StreamWriter sw = new StreamWriter(@"..\robots\GpRobot\" + csName + ".cs");
            sw.WriteLine(code);
            sw.Close();
        }


        //OnScannedRobot()  中的 MoveTank(<GP#1>);

        public static void CompileCsToDLL(string csName, string dllName = null) 
        {
            string path = @"..\robots\GpRobot\" + csName + ".cs";

            FileInfo info = new FileInfo(path);

            if (info.Extension.ToLower() != ".cs") 
            {
                Console.WriteLine("Err: Source file must have a .cs extension.");
                return;
            }

            CSharpCodeProvider provider = new CSharpCodeProvider();

            if (string.IsNullOrEmpty(dllName)) dllName = String.Format(@"..\robots\{0}.dll", csName.Replace('.', '_'));
            else dllName = String.Format(@"..\robots\{0}.dll", dllName);

            CompilerParameters cp = new CompilerParameters();
            cp.GenerateExecutable = false;
            cp.OutputAssembly = dllName;
            cp.GenerateInMemory = false;
            cp.TreatWarningsAsErrors = false;
            cp.ReferencedAssemblies.Add(@"..\robocode.dll");
            CompilerResults cr = provider.CompileAssemblyFromFile(cp, path);

            if (cr.Errors.Count > 0)
            {
                // Display compilation errors.
                Console.WriteLine("Errors building {0} into {1}", csName, cr.PathToAssembly);
                foreach (CompilerError ce in cr.Errors)
                {
                    Console.WriteLine("  {0}", ce.ToString());
                    Console.WriteLine();
                }
            }
            else
            {
                // Display a successful compilation message.
                Console.WriteLine("Source {0} built into {1} successfully.", csName, cr.PathToAssembly);
            }
        }
        #endregion
    }
}

